package com.esdk.sql.datasource;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.alibaba.druid.wall.spi.MySqlWallProvider;
import com.esdk.esdk;
import com.esdk.sql.ConnectionBuilder;
import com.esdk.sql.SQLRuntimeException;
import com.esdk.utils.EasyProp;

import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DataSourceBuilder{
  public final static String datasourceClass="dataSourceClass",DriverClass=ConnectionBuilder.DriverClass,Url=ConnectionBuilder.Url,User=ConnectionBuilder.User,UserName=ConnectionBuilder.UserName,Password=ConnectionBuilder.Password
  		,MaxActive="datasource.maxActive",MinIdle="datasource.minIdle",InitialSize="datasource.initialSize",MaxWaitMillis="datasource.maxWait";

  public static DataSource createDataSource(File configfile) throws Exception{
    return createDataSource(getProperty(configfile));
  }
  
  public static DataSource createDataSource(String propFileName) throws Exception{
  	return createDataSource(esdk.file.getInputStream(propFileName));
  }
  
  public static DataSource createDataSource(InputStream is) throws Exception{
    Properties prop=new Properties();
    prop.load(is);
    is.close();
    return createDataSource(prop);
  }

  public static DataSource createDataSource(EasyProp easyProp){
    DataSource dataSource=setupDataSource(easyProp);
    printStatus(dataSource);
    return dataSource;
  }

  public static DataSource createDataSource(Properties prop){
  	DataSource dataSource=setupDataSource(new EasyProp(prop));
    printStatus(dataSource);
    return dataSource;
  }
  
  static Properties getProperty(File propFile)throws IOException{
    Properties result=new Properties();
    FileInputStream fis=new FileInputStream(propFile);
    result.load(fis);
    fis.close();
    return result;
  }

  static DataSource setupDataSource(EasyProp prop) {
  	if(prop.containsKey("spring.datasource.url")) {
  		prop.put(Url,prop.get("spring.datasource.url"));
  		prop.put(DriverClass,prop.get("spring.datasource.driver-class-name"));
  		prop.put(User,prop.get("spring.datasource.username"));
  		prop.put(Password,prop.get("spring.datasource.password"));
  	}else if(prop.containsKey("jdbc.url")) {
  		prop.put(Url,prop.get("jdbc.url"));
  		prop.put(DriverClass,prop.get("jdbc.driverClass"));
  		prop.put(User,prop.get("jdbc.username"));
  		prop.put(Password,prop.get("jdbc.password"));
  	}else if(prop.containsKey(Url)){
			prop.put(Url,prop.get(Url));
			prop.put(DriverClass,prop.get(DriverClass));
			prop.put(User,prop.get(UserName));
			prop.put(Password,prop.get(Password));
		}
  	DruidDataSource ds=prop.containsKey(datasourceClass)?(DruidDataSource)esdk.reflect.safeNewInstance(prop.getString(datasourceClass)):new DruidDataSource();
    ds.setDriverClassName(prop.getString(DriverClass));
    ds.setUrl(prop.getString(Url));
    ds.setUsername(prop.getString(User));
    ds.setPassword(prop.getString(Password));
    ds.setMaxActive(Integer.valueOf(prop.getString(MaxActive,EasyConnectionPool.DefaultMaxConnections+"")));
    ds.setMinIdle(Integer.valueOf(prop.getString(MinIdle,"1")));
    ds.setInitialSize(Integer.valueOf(prop.getString(InitialSize,"1")));
    ds.setMaxWait(Integer.valueOf(prop.getString(MaxWaitMillis,"120000"))); //如果不设置的话，默认为-1，即无限等待，建议设为2分钟比较合适。
    ds.setUseGlobalDataSourceStat(esdk.prop.getBoolean("druid.useGlobalDataSourceStat",false));
    try{
      ds.setFilters(prop.getString("druid.filters"));
      for(Filter proxyFilter: ds.getProxyFilters()){
        if(proxyFilter instanceof WallFilter wallFilter){
          WallConfig wallConfig=new WallConfig(MySqlWallProvider.DEFAULT_CONFIG_DIR);
          wallConfig.setNoneBaseStatementAllow(prop.getBoolean("druid.filter.wall.noneBaseStatementAllow",false)); //允许ANALYZE TABLE tableName
          wallConfig.setStrictSyntaxCheck(prop.getBoolean("druid.filter.wall.strictSyntaxCheck",true)); // 按需关闭严格语法检查
          wallConfig.setSelectWhereAlwayTrueCheck(prop.getBoolean("druid.filter.wall.selectWhereAlwayTrueCheck",false)); //允许where 1=1 或 1>0之类
          if(prop.getString(Url).contains("allowMultiQueries=true")||prop.getBoolean("druid.filter.wall.multiStatementAllow",false)){
            wallConfig.setMultiStatementAllow(true);
            if(!prop.getString(Url).contains("allowMultiQueries=true"))
              esdk.warn("注意：如须执行批量sql，必须在jdbc.url添加："+"allowMultiQueries=true");
          }
          wallFilter.setConfig(wallConfig);
          break;
        }
      }
    }catch(SQLException e){
      throw new SQLRuntimeException(e);
    }
    return ds;
  }

  public static String getStatus(DataSource ds){
  	String msg =null;
    if(ds instanceof DruidDataSource) {
    	DruidDataSource dataSource=(DruidDataSource)ds;
      msg = dataSource.getUrl()+", account:"+esdk.str.desensitize(dataSource.getUsername())
        +", minIdle:"+dataSource.getMinIdle()+", maxActive:"+dataSource.getMaxActive()+", activeCount:"
        +dataSource.getActiveCount();
    }
    return msg;
  }
  
  public static void printStatus(DataSource ds){
    esdk.sout(getStatus(ds));
  }
  
  public static void main(String[] args) throws Exception{
  	DataSource ds=new DataSourceBuilder().createDataSource("db.properties");
  	Connection conn=ds.getConnection();
  	conn.setAutoCommit(false);
  	printStatus(ds);
	}
}
